﻿package com.components.form
{	
	/**
	 * @auth Chunning
	 * @purpose REGISTER FORM LOGIC....
	 * @date 2009-3-22
	 * */
	
	import com.components.button.MCButton;
	import com.components.form.element.IdentifyingCode;
	
	import debug.Log;
	
	import flash.display.DisplayObject;
	import flash.display.InteractiveObject;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.FocusEvent;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFieldType;
	
	import utils.data.DataUtils;
	import utils.focus.FocusManager;
	
	/** events of form **/
	[Event(name="is_blank", type="com.components.form.FormEvents")]
	[Event(name="repeat_not_match", type="com.components.form.FormEvents")]
	[Event(name="identify_code_wrong", type="com.components.form.FormEvents")]
	[Event(name="email_unavailabel", type="com.components.form.FormEvents")]
	[Event(name="submit", type="com.components.form.FormEvents")]
	[Event(name="cancel", type="com.components.form.FormEvents")]

	public class FormController extends EventDispatcher
	{
		//START
		
		//PROPERTY
				
		static public var tabIndex:uint = 100;
		
		private var formItems:Object = new Object;
		
		private var controls:Object = new Object;
		
		private var infos:Object = new Object;
		
		public var name:String;
		
		public var target:Sprite;
		
		private var autoCheck:Boolean;
		
		private var _submit:Function;
		
		private var _cancel:Function;
		
		private var lastItem:FormItem;
		
		private var _focus:FocusManager;
		
		private const NUM:String = "0-9";
		
		private const LETTER:String = "a-z A-Z";
		
		private const EMAIL:String = "a-z A-Z 0-9 @ . _";
		
		private const CHINESE:String = "\u4E00-\u9FA5";
		
				
		//CONSTRUCTOR
		public function FormController(target:Sprite,name:String,autoCheck:Boolean = false)
		{
			
			this.autoCheck = autoCheck;
			
			this.name = name;
						
			this.target = target;
			
			this.submit = submit;
			
			this.cancel = cancel;
			
			this._focus = new FocusManager(this.target);
						
			this.init();
			
		}
		
		//METHODS
		
		//init...
		private function init():void
		{
			
			var fontName:String;
			
			var backName:String;
			
			var formItem:FormItem;
			
			var check:Function;
			
			for(var i:uint;i < this.target.numChildren;i++)
			{
									
				fontName = this.getFrontName(this.target.getChildAt(i));
						
				
				if(fontName == this.name)
				{
					
					backName = this.getBackName(this.target.getChildAt(i));
															
					if(this.target.getChildAt(i) is TextField && (this.target.getChildAt(i) as TextField).type == TextFieldType.INPUT)
					{
						
						formItem = new FormItem(this.target.getChildAt(i) as TextField,this,backName);
						
						formItem.item.restrict = getTypeName(this.target.getChildAt(i));
						
						this.formItems[backName] = formItem;
												
						if(this.autoCheck)
						{
							
							formItem.addCheckMethods(InternalCheckManager.checkList);
							
							check = InternalCheckManager.getMthodByName(backName);
							
							if(check is Function)
							{
																
								formItem.addCheckMethod(check,backName);
								
							}
							
						}
												
						formItem.item.addEventListener(FocusEvent.FOCUS_OUT,formItemFocusOutHandler,false,0,true);
						
						formItem.item.addEventListener(FocusEvent.FOCUS_IN,itemFocusInHandler,false,0,true);
						
						formItem.item.addEventListener(MouseEvent.CLICK,itemFocusInHandler,false,0,true);
											
								
					}else{
						
						controls[backName] = target.getChildAt(i);
						
						(controls[backName] as MovieClip)["controller"] = new MCButton(controls[backName] as MovieClip);
												
						switch(backName)
						{
							
							case "refresh":
							
							this.controls[backName].addEventListener(MouseEvent.CLICK,refreshIdentCode);
							
							break;
							
							case "submit":
							
							this.controls[backName].addEventListener(MouseEvent.CLICK,onSumitClick);
														
							break;
							
							case "cancel":
							
							this.controls[backName].addEventListener(MouseEvent.CLICK,onCancelClick);
							
							break;
								
						}
						
						
					}
														
				}	
				
				if(fontName == "info" && this.target.getChildAt(i) is TextField)
				{
					
					backName = this.getBackName(this.target.getChildAt(i));
					
					this.infos[backName] = this.target.getChildAt(i);
					
				}	
				
			}
			
			this.target.addEventListener(KeyboardEvent.KEY_DOWN,keyDownHandler);
						
			this.specialRules();
		}
		
			
		
		//item click handler...
		private function itemFocusInHandler(evt:Event):void
		{
						
			var tf:TextField = evt.currentTarget as TextField;
			
			if(tf.text.length > 0)
			{
				
				tf.setSelection(0,tf.text.length);
				
			}
					
		}
		
		//on press enter key...
		private function keyDownHandler(evt:KeyboardEvent):void
		{
			
			if(evt.keyCode == 13 && this.getConsoleByName("submit") is Sprite)
			{
				
				this.getConsoleByName("submit").dispatchEvent(new MouseEvent(MouseEvent.CLICK));		
				
			}
			
		}
		
		//set Tab index...
		private function setTabIndex():void
		{
			
			var index:uint;
			
			for(var prop:String in this.formItems)
			{
				index = 1;
					
				for(var prop2:String in this.formItems)
				{
										
					if(prop2 == prop)
					{
						continue;																		
						
					}
										
					if(formItems[prop2].item.y < formItems[prop].item.y)
					{
						
						index++;
						
					}
					
					if(formItems[prop2].item.y == formItems[prop].item.y && formItems[prop2].item.x < formItems[prop].item.x)
					{
						
						index++;
						
					}
					
				}
												
				(formItems[prop].item as InteractiveObject).tabIndex = index;
				
				(formItems[prop].item as InteractiveObject).tabEnabled = false;
																																
			}
			
									
		}
				
		//speical rules...
		private function specialRules():void
		{
			
			if(this.formItems.hasOwnProperty("password") && this.formItems.hasOwnProperty("repassword"))
			{
				
				var item:FormItem = this.formItems["password"];
				
				var unit:FormItem = this.formItems["repassword"];
				
				item.unitCheckItem = unit;
				
			}
						
		}
				
		
		//on click submit button...
		private function onSumitClick(evt:MouseEvent):void
		{
													
			this.focus.setFocus(evt.currentTarget as InteractiveObject);
						
			if(this._submit is Function && this.isCorrect )
			{
				
				var data:Object = this.data;
								
				this.dispatchEvent(new FormEvents(FormEvents.SUBMIT,null));
				
				this._submit(data);	
											
			}
					
		}
		
		//on click cancel button...
		private function onCancelClick(evt:MouseEvent):void
		{
						
			if(this._cancel is Function)
			{
				
				this.dispatchEvent(new FormEvents(FormEvents.CANCEL,null));
				
				this._cancel();	
				
			}
					
		}
		
		//refresh identify code...
		private function refreshIdentCode(evt:MouseEvent):void
		{
									
			if(this.controls.hasOwnProperty("code") && this.controls["code"] is IdentifyingCode)
			{
				
				(this.controls["code"] as IdentifyingCode).refresh();	
				
			}
			
		}
		
		//on form item focus out...
		private function formItemFocusOutHandler(evt:FocusEvent):void
		{	
											
			var name:String = this.getBackName(evt.currentTarget as DisplayObject);
			
			var item:FormItem = this.formItems[name];
																								
			if(item is FormItem)
			{
				
				item.reset();
								
				if(item.unitCheckItem is FormItem)
				{
					
					item.unitCheckItem.reset();
																				
				}
				
			}
			
		}
		
		//get front name...
		private function getFrontName(item:DisplayObject):String
		{
			
			var name:String = item.name.split("$")[0];
			
			return name.split("_")[0];
			
		}
		
		//get backName...
		private function getBackName(item:DisplayObject):String
		{
			
			var name:String = item.name.split("$")[0];
			
			var names:Array = name.split("_");
			
			names.splice(0,1);
			
			return names.join("_");
			
		}
		
		
		// get Type name...
		private function getTypeName(item:DisplayObject):String
		{
			
			var type:String = item.name.split("$")[1];
			
			var types:Array =  type.split("_");
			
			var restrics:Array = new Array;
			
			for each(var t:String in types)
				
				restrics.push(this[t]);

			return restrics.join(" ");	
			
		}
		
		//get focus...
		private function get focus():FocusManager
		{
						
			return this._focus;
					
		}
		
		//check...
		public function get isCorrect():Boolean
		{
			
			var item:FormItem;
			
			var items:Array = new Array;
			
			for each(var frmItem:FormItem in formItems)
				
				items.push(frmItem);
			
			var items2:Array = [items[0]];	
				
			for(var i:int = 1;i < items.length;i++)
			{
				
				var frmItem2:FormItem = items[i];
								
				items2[i] = frmItem2;
				
				for(var j:int = 0;j < i;j++)
				{
					var comItem:FormItem = items2[j];
										
					if(comItem.item.y > frmItem2.item.y && Math.abs(comItem.item.y - frmItem2.item.y) >= Math.min(frmItem2.item.height,comItem.item.height))
					{
						items2.splice(j,0,frmItem2);

						items2.pop();
						
						break;
						
					}
					
					if(Math.abs(comItem.item.y - frmItem2.item.y) < Math.min(frmItem2.item.height,comItem.item.height) && comItem.item.x > frmItem2.item.x)
					{
						
						items2.splice(j,0,frmItem2);
						
						items2.pop();
						
						break;
						
					}
					
				}
				
			}
			
			for(var u:int = 0;u<items2.length;u++)
			{
				
				Log.log(items2[u].item.y + "," + items2[u].item.x,items2[u].name,Log.LOG_WARN);
			}
			
			for(var k:int = 0;k < items2.length;k++)
			{
				
				item = items2[k];
				
				if(!item.isCorrect)
				{	
					
					if(item.isLoading)
					{
						
						return false;
						
					}					
					
					this.focus.setFocus(item.item);
					
					item.item.setSelection(0,item.item.text.length);
					
					item.reset();
					
					return false;
					
				}
				
			}
			
			return true;
			
		}
		
		//get data...
		public function get data():Object
		{
			
			var _data:Object = new Object;
						
			for(var prop:String in this.formItems)
			{
				
				_data[prop] = DataUtils.trim(this.formItems[prop].item.text);
				
			}
			
			return _data;
		}
		
		//add hand check...
		public function addCheck(name:String,check:Function,checkName:String):void
		{
			
			var item:FormItem = this.formItems[name] as FormItem;
			
			item.addCheckMethod(check,checkName);
			
		}
		
		//remove check..
		public function removeCheckByName(name:String,checkName:String):void
		{
			
			var item:FormItem = this.formItems[name] as FormItem;
			
			item.removeCheckByName(checkName);
			
		}
		
		//get item by name...
		public function getItemByName(name:String):FormItem
		{
			
			return (this.formItems[name] as FormItem);			
			
		}
		
		//get consol by name...
		public function getConsoleByName(name:String):DisplayObject
		{
			
			return (this.controls[name] as DisplayObject);
			
		}
		
		//get info blank by name....
		public function getInfoByName(name:String):TextField
		{
			
			var txtInfo:TextField;
			
			if(this.infos.hasOwnProperty(name))
			{
				
				txtInfo = this.infos[name];
					
			}else{
				
				txtInfo = new TextField;
				
			}
			
			return txtInfo;
			
		}
		
		//set submit method....
		public function set submit(val:Function):void
		{
			
			this._submit = val;
			
			
		}
		
		//get submit method...
		public function get submit():Function
		{
			
			return this._submit;
				
			
		}
		
		//set cancel method...
		public function set cancel(val:Function):void
		{
			
			this._cancel = val;
			
		}
		
		//get cancel method...
		public function get cancel():Function
		{
			
			return this._cancel;
			
		}
		
		//reset form...
		public function resetForm():void
		{
			
			for each(var item:Object in this.formItems)
			{
				
				if(item is FormItem)
				{
					
					item.item.text  = item.defaultContent; 
					
					item.isCorrect = false;
					
					(item.item as TextField).scrollH = 0;
										
					if(item.isPassword)
					{
						
						item.item.displayAsPassword = false;
						
					}
														
				}
								
			}
			
			for each(var infoItem:Object in this.infos)
			{
				
				if(infoItem is TextField)
				{
					
					infoItem.text = "";
					
				}
				
			}
			
			for each(var console:Object in this.controls)
			{
				
				if(console.hasOwnProperty("refresh") && console["refresh"] is Function)
				{
					
					console.refresh();
					
				}
				
			}
			
			
		}
	
		
		//END
	}
}